#include "dominion.h"
#include <stdio.h>
#include "rngs.h"
#include <stdlib.h>
#include "math.h"
#include "dominion_helpers.h"
#include <assert.h>

int test1; //testing newgame() with the malloc function
int test2; //tests initializeGame()

void printGameState(struct gameState *g, FILE *fp){
	/*number of players
	  int numPlayers; //number of players
  int supplyCount[treasure_map+1];  //this is the amount of a specific type of card given a specific number.
  int embargoTokens[treasure_map+1];
  int outpostPlayed;
  int outpostTurn;
  int whoseTurn;
  int phase;
  int numActions;  Starts at 1 each turn 
  int coins;  Use as you see fit! 
  int numBuys; Starts at 1 each turn 
  int hand[MAX_PLAYERS][MAX_HAND];
  int handCount[MAX_PLAYERS];
  int deck[MAX_PLAYERS][MAX_DECK];
  int deckCount[MAX_PLAYERS];
  int discard[MAX_PLAYERS][MAX_DECK];
  int discardCount[MAX_PLAYERS];
  int playedCards[MAX_DECK];
  int playedCardCount;
	all kingdom cards and the number in each stack
	*/
	int i;
	int j;
	fprintf(fp, "****GAME STATE****\n");
	fprintf(fp, "Number of Players: %d\n", g->numPlayers);
	fprintf(fp, "Supply Count:\n");
	for(i=0; i<treasure_map + 1; i++){
		fprintf(fp, "	Card: %d Amount: %d\n", i, g->supplyCount[i]);
	}
	fprintf(fp, "Embargo Tokens\n");
	for(i=0; i<treasure_map +1; i++){
		fprintf(fp, "	Card: %d Tokens: %d\n", i, g->embargoTokens[i]);
	}
	fprintf(fp, "Outpost Played Status: %d\n", g->outpostPlayed);
	fprintf(fp, "Outpost Turn: %d\n", g->outpostTurn);
	fprintf(fp, "Phase: %d\n", g->phase);
	fprintf(fp, "Actions: %d\n", g->numActions);
	fprintf(fp, "Coins: %d\n", g->coins);
	fprintf(fp, "Buys: %d\n", g->numBuys);
	fprintf(fp, "HANDS\n");
	for(i=0; i< g->numPlayers; i++){
		fprintf(fp, "	Player %d Hand Count: %d\n    Hand: ", i, g->handCount[i]);
		for(j=0; j < g->handCount[i]; j++){
			fprintf(fp, "%d, ", g->hand[i][j]);
		//	if(j % 10 == 0 && j != 0){
		//		fprintf(fp, "\n          ");
		//	}
		}
		fprintf(fp, "\n");
	}
	fprintf(fp, "DECKS\n");
	for(i=0; i< g->numPlayers; i++){
		fprintf(fp, "	Player %d Deck Count: %d\n    Deck: ", i, g->deckCount[i]);
		for(j=0; j < g->deckCount[i]; j++){
			fprintf(fp, "%d, ", g->deck[i][j]);
		//	if(j % 10 == 0 && j != 0){
		//		fprintf(fp, "\n          ");
		//	}
		}
		fprintf(fp, "\n");
	}
	fprintf(fp, "DISCARDS\n");
	for(i=0; i< g->numPlayers; i++){
		fprintf(fp, "	Player %d Discard Count: %d\n    Discard: ", i, g->discardCount[i]);
		for(j=0; j < g->discardCount[i]; j++){
			fprintf(fp, "%d, ", g->discard[i][j]);
		//	if(j % 10 == 0 && j != 0){
		//		fprintf(fp, "\n          ");
		//	}
		}
		fprintf(fp, "\n");
	}
	fprintf(fp, "Played Count: %d\n    Played Cards: ", g->playedCardCount);
	for(i=0; i < g->playedCardCount; i++){
		fprintf(fp, "%d, ", g->playedCards[i]);
	//	if(i % 10 == 0 && i != 0){
	//		fprintf(fp, "\n     ");
	//	}
	}
	fprintf(fp, "\n");
}



void prepRandom(int strm, int seed){
  SelectStream(strm);
  PutSeed((long)seed);
}

int getRandomNumber(int min, int max){
	int number = floor(Random() * ((max-min)+1));
	number += min;
	if(number > max){
		number = max;
	}
	return number;

}

//returns 1 if the card is in the deck, 0 if not

int notCalledYet(int *k, int card, int top){
	int i;
	for(i=0; i < top; i++){
		if(card == k[i]){
			return 0;
		}
	}
	return 1;
}

int coinsInHand(struct gameState *g){
	int coins;
	int i;
	for(i = 0; i < g->handCount[g->whoseTurn]; i++){
		if(g->hand[g->whoseTurn][i] == copper){
			coins ++;
		}
		if(g->hand[g->whoseTurn][i] == silver){
			coins = coins + 2;
		}
		if(g->hand[g->whoseTurn][i]== gold){
			coins = coins + 3;
		}
	}
	return coins;
}

void getRandomOrder(int *array, int length){

	int i;
	int j;
	int current;
	int temp;

	/*printf("order before:\n");
	for(i=0; i<length; i++){
		printf("%d\n", array[i]);
	}
	*/
	for(j=0; j<1000; j++){
		for(i=0; i<length; i++){
			current = getRandomNumber(0, (length - 1));
			temp = array[i];
			array[i] = array[current];
			array[current] = temp;
		}
	}
	/*
	printf("order after:\n");
	for(i=0; i<length; i++){
		printf("%d\n", array[i]);
	}
	*/
}
//prints the hand of selected player
void printHand(struct gameState *g, int player){
	int i;
	printf("Player %d's hand:\n", player);
	int count = g->handCount[player];
	for(i=0; i< count; i++){
		printf("%d, ", g->hand[player][i]);
	}
	printf("\n");
}

int shopForCard(struct gameState *g){
	int result = -1;
	int i;
	printf("	buys available: %d\n", g->numBuys);
	printf("	coins available: %d\n", g->coins);
	
	if(g->coins >= 8){
		result = buyCard(province, g);
		if(result == 0) {
			printf("	Providence Purchased\n");
			return 1;
		}
	}
	if(g->coins >= 6){
		if(getRandomNumber(0,1) == 0){
			result = buyCard(adventurer, g);
			if(result == 0){
				printf("	Adventurer Purchased\n");
				return 1;
			} 
		}
		result = buyCard(gold, g);
		if(result == 0){
			printf("	Gold Purchased\n");
		 	return 1;
		}
	}
	if(g->coins >= 5){
		int random[6] = {duchy, council_room, mine, minion, tribute, outpost};
		printf("Attempting to purchase cards of cost 5.\n Setting order to attempt:\n");
		getRandomOrder(random, 6);

		for(i=0; i<6; i++){
			printf("	Attempting to buy %d\n", random[i]);
			result = buyCard(random[i], g);
			if(result == 0){
				printf("		Purchase successful\n");
				break;
			}
			
		}
		if(result == 0) return 1;
	}
	if(g->coins >= 4){
		int random[9] = {feast, gardens, remodel, smithy, baron, cutpurse, salvager, sea_hag, treasure_map};
		getRandomOrder(random, 9);
		for(i=0; i<9; i++){
			printf("	Attempting to buy %d\n", random[i]);
			result = buyCard(random[i], g);
			if(result == 0){
				printf("		Purchase successful\n");
				break;
			}
			
		}
		if(result == 0) return 1;
	}
	if(g->coins >=3){
		int random[5] = {silver, village, great_hall, steward, ambassador};
		getRandomOrder(random, 5);
		for(i=0; i<5; i++){
			printf("	Attempting to buy %d\n", random[i]);
			result = buyCard(random[i], g);
			if(result == 0){
				printf("		Purchase successful\n");
				break;
			}
			
		}
		if(result == 0) return 1;
	}
	if(g->coins >=2){
		int random[2] = {embargo, estate};
		getRandomOrder(random, 2);
		for(i=0; i<2; i++){
			printf("	Attempting to buy %d\n", random[i]);
			result = buyCard(random[i], g);
			if(result == 0){
				printf("		Purchase successful\n");
				break;
			}
			
		}
		if(result == 0) return 1;
	}
	if(g->coins >=0){
		printf("	Attempting to buy %d\n", copper);
		result = buyCard(copper, g);
		if(result == 0){
			printf("		Purchase successful.\n");
			return 1;
		}

	}
	return 0;

}

//returns the position of the card being searched
// or -1 if not found
int searchHand(struct gameState *g, int player, int card){
	int i;
	for(i=0; i<g->handCount[player]; i++){
		if(g->hand[player][i] == card){
			return i;
		}
	}
	return -1;
}
int howManyInHand(struct gameState*g, int player, int card){
	int i;
	int count = 0;
	for(i=0; i<g->handCount[player]; i++){
		if(g->hand[player][i] == card){
			count++;
		}
	}
	return count;
}
/*Chooses cards with actions first.
	Returns the handpos to play or -1 if none to play
Cards with +actions: village, great hall, minion, 
*/ 
int chooseCardToPlay(struct gameState *g){
	printf("Action Phase*****\n");
	int i;
	for(i=0; i<g->handCount[g->whoseTurn]; i++){
		if(g->hand[g->whoseTurn][i] == village || g->hand[g->whoseTurn][i] == great_hall || g->hand[g->whoseTurn][i] == minion){
			return i;
		}		
	}
	for(i=0; i<g->handCount[g->whoseTurn]; i++){
		if(g->hand[g->whoseTurn][i] > gold){
			if(g->hand[g->whoseTurn][i] < gardens){
				return i;
			}
		}
		if(g->hand[g->whoseTurn][i] > gardens){
			if(g->hand[g->whoseTurn][i] < treasure_map+1){
				return i;
			}
		}

	}
	return -1;
}
int feastChooser(struct gameState *g, int *k){
	int choice;
	return choice;
}
int remodelChooser1(struct gameState *g){
	return 0;
}
//returns silver if there is one,
//returns copper if copper and no silver
// or -1 if none
int mineChooser1(struct gameState *g){
	int i;
	int choice = -1;
	for(i=0; i<g->handCount[g->whoseTurn]; i++){
		if(g->hand[g->whoseTurn][i] == silver){
			return i;
		}
		if(g->hand[g->whoseTurn][i] == copper){
			choice = i;
		}
	}
	return choice;
}
int baronChooser(struct gameState *g){
	int i;
	for(i=0; i < g->handCount[g->whoseTurn]; i++){
		if(g->hand[g->whoseTurn][i] == estate){
			return 1;
		}
	}
	return 0;
}
//cards with choices
//returns choice 1
int makeChoice1(struct gameState *g, int pos, int *k){
	int card = g->hand[g->whoseTurn][pos];
	if(card == feast){
		return feastChooser(g, k);
	}
	if(card == mine){
		return mineChooser1(g);
	}
	if(card == remodel){
		return remodelChooser1(g);
	}
	if(card == baron){
		return 0;
	}
	return 0;
}
//counts how many of a specific card are in a set, returns the number
//set: hand = 1, deck = 2, discard = 3, playedCards = 4, all = 5
int countCardsInSet(struct gameState *g, int player, int card, int set){
	int i;
	int count = 0;
	if(set == 1 || set == 5){//counts specific card in the hand
		for(i=0; i<g->handCount[player]; i++){
			if(g->hand[player][i] == card){
				count ++;
			}
		}
	}
	if(set == 2 || set == 5){//counts specific card in the deck
		for(i=0; i<g->deckCount[player]; i++){
			if(g->deck[player][i] == card){
				count ++;
			}
		}
	}
	if(set == 3 || set == 5){//counts specific card in the discard
		for(i=0; i<g->discardCount[player]; i++){
			if(g->discard[player][i] == card){
				count ++;
			}
		}
	}
	if(g->whoseTurn == player){
		if(set == 4 || set == 5){//counts specific card in the hand
			for(i=0; i<g->playedCardCount; i++){
				if(g->playedCards[i] == card){
					count ++;
				}
			}
		}
	}
	return count;
}

int testInitialize(struct gameState *g, int players, FILE *fp){
	int results = 1;
	int i;
	if(players != g->numPlayers){
		fprintf(fp, "Player initialization failed! Expected: %d Actual: %d", players, g->numPlayers);
		results = 0;
	}	
	for(i=0; i<players; i++){

	}
	if(players == 2){

	}
	return results;
}



 int playGame(int seed, FILE *fp){
	fprintf(fp, "****BEGINNING NEW GAME****\n");
	struct gameState *g = newGame();
	//if(g == NULL){
	//	fprintf(fp, "newGame failed\n");
	//	test1 ++;
	//}
	int strm = 2;

	prepRandom(strm, seed);
	int i;
	int kingdomCard;
	int k[10];
	getRandomNumber(0, 1); //burn the initial random number
	for(i=0; i<10; i++){
		kingdomCard = getRandomNumber(7, 26);
		while(notCalledYet(k, kingdomCard, i) == 0){
			kingdomCard = getRandomNumber(7, 26);
		}
		k[i] = kingdomCard;
	}
	int players = getRandomNumber(2, 4);
	//print kingdom cards
	printf("Kingdom Cards:\n");
	for(i=0; i<10; i++){
		printf("card %d: %d\n", i, k[i]);
	}
	printf("players: %d\n", players);
	printf("Starting Dominion\n");
	int gameSeed = getRandomNumber(1, 1000000);
	initializeGame(players, k, gameSeed, g);

	assert(players > 1 && players < 5 );
	assert(players == g->numPlayers);
	//testHandDeck(g);
	//testK(g, k);
	//testVictoryCards(g);
	/*check for proper number of cards in all areas
	check to see that hand->size matches the actual size
	supply should have 10 of each victory card
	coin cards-- at least 30?
	10 sets of 10 Kingdom cards
	*/

	printf("Game Initialized\n");
	printGameState(g, fp);
	int coins;
	int actions;
	int buys;
	int choice1;
	int choice2;
	int choice3;
	int result = -1;
	int cardToPlay;
	int cardChosen;
	int roundNumber = 0;
	//int buyAttempt;
	
	//int cardToBuy;
	int quit = 2;
	while(!isGameOver(g) && quit != 0){
		if(g->whoseTurn == 0){
			roundNumber ++;
		}
		printf("Player %d's turn\n", g->whoseTurn);
		coins = 0;
		actions = 1;
		buys = 1;
		//count money
		updateCoins(g->whoseTurn, g, 0);
		//coins = coinsInHand(g);
		printHand(g, g->whoseTurn);
		printf("	coins: %d\n", g->coins);
		printf("	actions: %d\n", g->numActions);
		printf("	buys: %d\n", g->numBuys);
		printf("Actions Phase:\n");
		while(g->numActions > 0){
			//do actions round
			cardToPlay = chooseCardToPlay(g); //find hand position
		//	choice1 = makeChoice1(g, cardToPlay, k);
			cardChosen = g->hand[g->whoseTurn][cardToPlay];


			printf("	Card Chosen: %d\n", cardChosen);
			if(cardChosen == treasure_map){
				if(howManyInHand(g, g->whoseTurn, cardChosen)){
					printf("Dumping treasure_map\n");
					break;
				}
			}
			if(cardToPlay == -1){  //no action cards to play
				break;
			}
			fprintf(fp, "BEFORE PLAYING CARD %d FOR PLAYER %d, ROUND %d:\n", cardChosen, g->whoseTurn, roundNumber);
			printGameState(g, fp);
			result = -1;
			for(i=0; i< 15000; i++){ //7,290 possible combinations, most all should be covered with 15k
				choice1 = getRandomNumber(-1, 26);//choice 1 and 2 sometimes involve supply cards
				choice2 = getRandomNumber(-1, 26);
				choice3 = getRandomNumber(-1, 10);//choice 3 only involves the hand
				result = playCard(cardToPlay, choice1, choice1, choice3, g);
				if(result == 0){
					printf("%d played choice1: %d choice2: %d choice3: %d\n",cardChosen, choice1, choice2, choice3);
					if(cardChosen == tribute){
						discardCard(cardToPlay, g->whoseTurn, g, 0);
						printf("Discarding Tribute\n");
					}
					break;
				}
				//patch -- must remove if dominion.c is corrected
				

			}
			if(result == -1){
				discardCard(cardToPlay, g->whoseTurn, g, 0);
				printf("Could not play %d\n", cardChosen);
			}
			fprintf(fp, "AFTER PLAYING CARD %d FOR PLAYER %d:\n", cardChosen, g->whoseTurn);
			printGameState(g, fp);

			
		}

		while(g->numBuys > 0){
			// do buys round: one purchase per loop
			if(shopForCard(g) ==0){
				printf("No Card Purchased\n");
				//printf("Estate Cards = %d\n", g->supplyCount[1]);
				break;
			}
			
		}


		endTurn(g);

		//quit --;

	}
	int winnerCheck[MAX_PLAYERS];
	int score;
	getWinners(winnerCheck, g);
	printf("Number of Players(supposedly): %d\n", players);
	printf("Number of Players(actually): %d\n", g->numPlayers);
	for(i=0; i<g->numPlayers; i++){
		score = scoreFor(i, g);
		printf("Player %d score: %d\n", i, score);
	}
	for(i=0; i<MAX_PLAYERS; i++){
		if(winnerCheck[i] == 1){
			printf("Player %d wins!\n", i);
		}
	}
	fprintf(fp, "Game Over\n");
	free(g);
return 0;
}

int main (int argc, char** argv){
	int seed = 1;
	int rounds = 10;
	int i;
	if(argc > 1){
		rounds = atoi(argv[1]);
	}
	if(argc > 2){
		seed = atoi(argv[2]);
	}

	FILE *fp;
	char *fileName = "gameResults.out";
	fp = fopen(fileName, "w+");
	if(fp == NULL){
		perror("Error");
		exit(0);
	}
	fprintf(fp, "Testing Dominion: %d rounds, beginning with seed %d\n", rounds, seed);

	//printf("WTF\n");
	for(i=0; i<rounds; i++){
		playGame(seed, fp);
		seed++;
	}
	fprintf(fp, "Test Complete\n");
	fclose(fp);

return 0;
}
